//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.eResearch.WFServiceLibrary.SchedulerLogic
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using V1 = TaskScheduler.V1;
    using V2 = TaskScheduler;

    /// <summary>
    /// Collection that contains the actions that are performed by the task.
    /// </summary>
    public sealed class ActionCollection : IEnumerable<Action>, IDisposable
    {
        private V1.ITask v1TaskDefinition;
        private V2.ITaskDefinition v2TaskDefinition;
        private V2.IActionCollection actionCollection;

        /// <summary>
        /// Initializes a new instance of the <see cref="ActionCollection"/> class.
        /// </summary>
        /// <param name="task">The task.</param>
        internal ActionCollection(V1.ITask task)
        {
            v1TaskDefinition = task;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ActionCollection"/> class.
        /// </summary>
        /// <param name="iTaskDef">The i task def.</param>
        internal ActionCollection(V2.ITaskDefinition iTaskDef)
        {
            v2TaskDefinition = iTaskDef;
            actionCollection = iTaskDef.Actions;
        }

        /// <summary>
        /// Adds an action to the task.
        /// </summary>
        /// <param name="action">A derived <see cref="Action"/> class.</param>
        public Action Add(Action action)
        {
            if (v2TaskDefinition != null)
                action.Bind(v2TaskDefinition);
            else
                action.Bind(v1TaskDefinition);

            return action;
        }

        /// <summary>
        /// Gets the number of actions in the collection.
        /// </summary>
        public int Count
        {
            get
            {
                if (actionCollection != null)
                    return actionCollection.Count;
                return 1;
            }
        }

        /// <summary>
        /// Releases all resources used by this class.
        /// </summary>
        public void Dispose()
        {
            v1TaskDefinition = null;
            v2TaskDefinition = null;
            actionCollection = null;
        }

        /// <summary>
        /// Clears all actions from the task.
        /// </summary>
        public void Clear()
        {
            if (actionCollection != null)
                actionCollection.Clear();
            else
            {
                for (int i = this.Count - 1; i >= 0; i--)
                    RemoveAt(i);
            }
        }

        /// <summary>
        /// Removes the action at a specified index.
        /// </summary>
        /// <param name="index">Index of action to remove.</param>
        /// <exception cref="ArgumentOutOfRangeException">Index out of range.</exception>
        public void RemoveAt(int index)
        {
            if (index >= this.Count)
                throw new ArgumentOutOfRangeException("index", index, "Failed to remove Trigger. Index out of range.");

            if (actionCollection != null)
                actionCollection.Remove(++index);
        }

        #region IEnumerable<Action> Members

        /// <summary>
        /// Returns an enumerator that iterates through the collection.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used 
        /// to iterate through the collection.
        /// </returns>
        public IEnumerator<Action> GetEnumerator()
        {
            if (actionCollection != null)
                return new ActionEnumerator(this);

            return new ActionEnumerator(this.v1TaskDefinition);
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion

        internal class ActionEnumerator : IEnumerator<Action>
        {
            private V1.ITask v1Task;
            private int v1Pos = -1;
            private IEnumerator actionEnum;

            internal ActionEnumerator(V1.ITask task)
            {
                v1Task = task;
            }

            internal ActionEnumerator(ActionCollection iColl)
            {
                if (iColl.actionCollection != null)
                    actionEnum = iColl.actionCollection.GetEnumerator();
            }

            #region IEnumerator<Action> Members

            public Action Current
            {
                get
                {
                    if (actionEnum != null)
                    {
                        V2.IAction iAction = actionEnum.Current as V2.IAction;
                        if (iAction != null)
                            return Action.CreateAction(iAction);
                    }
                    if (v1Pos == 0)
                        return new ExecAction(v1Task.GetApplicationName(), v1Task.GetParameters(), v1Task.GetWorkingDirectory());

                    throw new InvalidOperationException();
                }
            }

            #endregion

            #region IDisposable Members

            public void Dispose()
            {
                v1Task = null;
                actionEnum = null;
                GC.SuppressFinalize(this);
            }

            #endregion

            #region IEnumerator Members

            object IEnumerator.Current
            {
                get { return this.Current; }
            }

            public bool MoveNext()
            {
                if (actionEnum != null)
                    return actionEnum.MoveNext();
                return ++v1Pos == 0;
            }

            public void Reset()
            {
                if (actionEnum != null)
                    actionEnum.Reset();
                v1Pos = -1;
            }

            #endregion
        }
    }
}
